<template>
    <div
        ref="floatDrag"
        class="float-position"
        :style="{
            left: state.left + 'px',
            top: state.top + 'px',
            zIndex: props.zIndex,
        }"
        @touchmove.prevent
        @mousemove.prevent
        @mousedown="mouseDown"
        @mouseup="mouseUp"
    >
        <div
            class="drag-tools-container"
            v-if="!showTools"
            @click.prevent="handleClick"
        >
            <SvgIcon name="logo" style="width: 100%; height: 100%"></SvgIcon>
        </div>
        <div class="drag-content-container" v-else @click.prevent>
            <slot></slot>
            <div class="slot-footer">
                <el-link href="#" style="font-size: 12px" underline>
                    设置
                </el-link>
                <el-link
                    href="#"
                    @click="changeShowTools"
                    style="font-size: 12px"
                    underline
                >
                    关闭
                </el-link>
            </div>
        </div>
    </div>
</template>

<script setup>
import { nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { debounce } from 'lodash-es'
import { ChromeSliderBarStorage } from '@/utils/handleChromeStorange'

const props = defineProps({
    distanceRight: {
        type: Number,
        default: 0,
    },
    distanceTop: {
        type: Number,
        default: 100,
    },
    isScrollHidden: {
        type: Boolean,
        default: false,
    },
    isCanDraggable: {
        type: Boolean,
        default: true,
    },
    zIndex: {
        type: Number,
        default: 99999999,
    },
})
const showTools = ref(false)
const floatDrag = ref(null)
const hasVerticalScrollBar = ref(false)
const state = reactive({
    clientWidth: null,
    clientHeight: null,
    left: 0,
    top: 0,
    timer: null,
    currentTop: 0,
    isMoving: false,
    mouseDownTime: 0,
    mouseUpTime: 0,
})
const changeShowTools = async () => {
    showTools.value = !showTools.value
    nextTick(() => {
        checkDraggablePosition()
    })
}

const handleClick = () => {
    // 只有在点击事件时才触发 changeShowTools
    console.log(
        `两次点击相差的时间间隔为${state.mouseUpTime - state.mouseDownTime}`,
    )
    if (state.mouseUpTime - state.mouseDownTime < 200) {
        changeShowTools()
    }
}

const initDraggable = () => {
    floatDrag.value.addEventListener('touchstart', toucheStart)
    floatDrag.value.addEventListener('touchmove', touchMove)
    floatDrag.value.addEventListener('touchend', touchEnd)
}

const handleScroll = () => {
    if (state.timer) clearTimeout(state.timer)
    state.timer = setTimeout(() => {
        handleScrollEnd()
    }, 200)
    state.currentTop =
        document.documentElement.scrollTop || document.body.scrollTop
    if (state.left > state.clientWidth / 2) {
        state.left =
            state.clientWidth + floatDrag.value.getBoundingClientRect().width
    } else {
        state.left = -floatDrag.value.getBoundingClientRect().width
    }
}

const handleScrollEnd = () => {
    const scrollTop =
        document.documentElement.scrollTop || document.body.scrollTop
    if (scrollTop === state.currentTop) {
        if (state.left > state.clientWidth / 2) {
            state.left =
                state.clientWidth -
                floatDrag.value.getBoundingClientRect().width
        } else {
            state.left = 0
        }
        clearTimeout(state.timer)
    }
}
const handleResize = () => {
    state.clientWidth = document.documentElement.clientWidth
    state.clientHeight = document.documentElement.clientHeight
    checkDraggablePosition()
}

const mouseDown = (e) => {
    if (showTools.value) return
    const event = e || window.event
    const floatDragWidth = floatDrag.value.getBoundingClientRect().width / 2
    const floatDragHeight = floatDrag.value.getBoundingClientRect().height / 2
    if (event.preventDefault) {
        event.preventDefault()
    }
    state.canClick = false
    state.mouseDownTime = new Date().getTime()
    floatDrag.value.style.transition = 'none'
    document.onmousemove = function(e) {
        const event = e || window.event
        state.left = event.clientX - floatDragWidth
        state.top = event.clientY - floatDragHeight
    }
}

const mouseUp = () => {
    if (showTools.value) return
    state.mouseUpTime = new Date().getTime()
    document.onmousemove = null
    checkDraggablePosition()
    floatDrag.value.style.transition = 'all 0.3s'
}

const toucheStart = () => {
    state.canClick = false
    floatDrag.value.style.transition = 'none'
}

const touchMove = (e) => {
    state.canClick = true
    if (e.targetTouches.length === 1) {
        const touch = e.targetTouches[0]
        state.left =
            touch.clientX - floatDrag.value.getBoundingClientRect().width / 2
        state.top =
            touch.clientY - floatDrag.value.getBoundingClientRect().height / 2
    }
}

const touchEnd = () => {
    if (!state.canClick) return
    floatDrag.value.style.transition = 'all 0.3s'
    checkDraggablePosition()
}

const checkDraggablePosition = () => {
    if (
        state.left + floatDrag.value.getBoundingClientRect().width / 2 >=
        state.clientWidth / 2
    ) {
        state.left =
            state.clientWidth - floatDrag.value.getBoundingClientRect().width
    } else {
        state.left = 0
    }
    if (state.top < 0) {
        state.top = 0
    }
    if (
        state.top + floatDrag.value.getBoundingClientRect().height >=
        state.clientHeight
    ) {
        state.top =
            state.clientHeight - floatDrag.value.getBoundingClientRect().height
    }

    ChromeSliderBarStorage.set({
        left: state.left,
        top: state.top,
    })
    debouncedFunction()
}

const debouncedFunction = debounce(() => {
    if (!showTools.value)
        state.left = state.left === 0 ? -14.4 : state.left + 14.4
}, 2000)

onMounted(() => {
    state.clientWidth = document.documentElement.clientWidth
    state.clientHeight = document.documentElement.clientHeight
    hasVerticalScrollBar.value =
        document.documentElement.scrollHeight > window.innerHeight

    if (props.isCanDraggable) {
        nextTick(async () => {
            const positionData = await ChromeSliderBarStorage.get()
            if (positionData) {
                state.left = positionData.left
                state.top = positionData.top
                checkDraggablePosition()
            } else {
                const floatDragDom = floatDrag.value.getBoundingClientRect()
                state.left =
                    state.clientWidth - floatDragDom.width - props.distanceRight
                state.top = props.distanceTop
            }
            debouncedFunction()
            initDraggable()
        })
    }

    if (props.isScrollHidden) {
        window.addEventListener('scroll', handleScroll)
    }
    window.addEventListener('resize', handleResize)
    const observer = new MutationObserver(checkScrollBarVisibility)

    // 监听整个文档的变化
    observer.observe(document.documentElement, {
        childList: true,
        subtree: true,
        attributes: true,
    })
})

const checkScrollBarVisibility = () => {
    const flag = document.documentElement.scrollHeight > window.innerHeight
    if (flag !== hasVerticalScrollBar.value) {
        hasVerticalScrollBar.value = flag
        handleResize()
    }
}

onBeforeUnmount(() => {
    window.removeEventListener('scroll', handleScroll)
    window.removeEventListener('resize', handleResize)
})
</script>

<style lang="scss" scoped>
.float-position {
    position: fixed;
}

.drag-tools-container {
    border-radius: 36px;
    background-color: #ff0000;
    width: 36px;
    height: 36px;
    box-sizing: border-box;
    padding: 8px 8px 10px 10px;
    display: flex;
    justify-content: center;
    align-content: center;
    opacity: 0.5;
    cursor: pointer;
}

.drag-content-container {
    width: 200px;
    height: 100%;
    padding: 20px 10px 20px 10px;
    box-sizing: border-box;
    border-radius: 10px;
    background-color: #fff;
    box-shadow: 0 0 10px 0 rgb(0 0 0 / 20%);

    .slot-footer {
        display: flex;
        width: 100%;
        justify-content: space-around;
        align-items: center;
        font-size: 12px !important;
        margin-top: 10px;
    }
}
</style>
